/**
 * Copyright (c) 2004-2006, Martin Fiedler.  All rights reserved.
 * Copyright (c) 2012, Ken Anderson.  All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **/
 
#include "common.h"
#include "slicehdr.h"
#include "mbmodes.h"

static int ISliceMbModes[][4]={
  {Intra_4x4,   NA, NA, NA},
  {Intra_16x16,  0,  0,  0},
  {Intra_16x16,  1,  0,  0},
  {Intra_16x16,  2,  0,  0},
  {Intra_16x16,  3,  0,  0},
  {Intra_16x16,  0,  1,  0},
  {Intra_16x16,  1,  1,  0},
  {Intra_16x16,  2,  1,  0},
  {Intra_16x16,  3,  1,  0},
  {Intra_16x16,  0,  2,  0},
  {Intra_16x16,  1,  2,  0},
  {Intra_16x16,  2,  2,  0},
  {Intra_16x16,  3,  2,  0},
  {Intra_16x16,  0,  0, 15},
  {Intra_16x16,  1,  0, 15},
  {Intra_16x16,  2,  0, 15},
  {Intra_16x16,  3,  0, 15},
  {Intra_16x16,  0,  1, 15},
  {Intra_16x16,  1,  1, 15},
  {Intra_16x16,  2,  1, 15},
  {Intra_16x16,  3,  1, 15},
  {Intra_16x16,  0,  2, 15},
  {Intra_16x16,  1,  2, 15},
  {Intra_16x16,  2,  2, 15},
  {Intra_16x16,  3,  2, 15},
  {NA, NA, NA, NA} // I_PCM
};

static int PSliceMbModes[][5]={
  {1, Pred_L0, NA,      16, 16},
  {2, Pred_L0, Pred_L0, 16,  8},
  {2, Pred_L0, Pred_L0,  8, 16},
  {4, NA,      NA,       8,  8},
  {4, NA,      NA,       8,  8},
  {1, Pred_L0, NA,      16, 16}  // P_Skip
};

static int PSliceSubMbModes[][4]={
  {1, Pred_L0, 8, 8},
  {2, Pred_L0, 8, 4},
  {2, Pred_L0, 4, 8},
  {4, Pred_L0, 4, 4},
};

int CodedBlockPatternMapping_Intra4x4[]={
  47,31,15, 0,23,27,29,30, 7,11,13,14,39,43,45,46,
  16, 3, 5,10,12,19,21,26,28,35,37,42,44, 1, 2, 4,
   8,17,18,20,24, 6, 9,22,25,32,33,34,36,40,38,41
};
int CodedBlockPatternMapping_Inter[]={
   0,16, 1, 2, 4, 8,32, 3, 5,10,12,15,47, 7,11,13,
  14, 6, 9,31,35,37,42,44,33,34,36,40,39,43,45,46,
  17,18,20,24,19,21,26,28,23,27,29,30,22,25,38,41
};


void decode_mb_mode(mb_mode *mb, int slice_type, int raw_mb_type) {
  #define INVALID_MB do { memset(mb,0xFF,sizeof(mb_mode)); return; } while(0)
  if(slice_type==I_SLICE) {
    if(raw_mb_type>25) INVALID_MB;
    mb->mb_type=raw_mb_type+5;
    mb->NumMbPart=1;
    mb->MbPartPredMode[0]=ISliceMbModes[raw_mb_type][0];
    mb->MbPartPredMode[1]=NA;
    mb->Intra16x16PredMode=ISliceMbModes[raw_mb_type][1];
    mb->MbPartWidth=16;
    mb->MbPartHeight=16;
    mb->CodedBlockPatternChroma=ISliceMbModes[raw_mb_type][2];
    mb->CodedBlockPatternLuma=ISliceMbModes[raw_mb_type][3];
  } else if(slice_type==P_SLICE) {
    if(raw_mb_type>4)
      decode_mb_mode(mb,I_SLICE,raw_mb_type-5);
    else {
      mb->mb_type=raw_mb_type;
      mb->NumMbPart=PSliceMbModes[raw_mb_type][0];
      mb->MbPartPredMode[0]=PSliceMbModes[raw_mb_type][1];
      mb->MbPartPredMode[1]=PSliceMbModes[raw_mb_type][2];
      mb->Intra16x16PredMode=NA;
      mb->MbPartWidth=PSliceMbModes[raw_mb_type][3];
      mb->MbPartHeight=PSliceMbModes[raw_mb_type][4];
      mb->CodedBlockPatternChroma=NA;
      mb->CodedBlockPatternLuma=NA;
    }
  } else
    INVALID_MB;
}

void decode_sub_mb_mode(sub_mb_mode *sub, int slice_type, int raw_sub_mb_type) {
  #define INVALID_SUB do { memset(sub,0xFF,sizeof(sub_mb_mode)); return; } while(0)
  if(slice_type==P_SLICE) {
    if(raw_sub_mb_type>3) INVALID_SUB;
    sub->sub_mb_type=raw_sub_mb_type;
    sub->NumSubMbPart=PSliceSubMbModes[raw_sub_mb_type][0];
    sub->SubMbPredMode=PSliceSubMbModes[raw_sub_mb_type][1];
    sub->SubMbPartWidth=PSliceSubMbModes[raw_sub_mb_type][2];
    sub->SubMbPartHeight=PSliceSubMbModes[raw_sub_mb_type][3];
  } else
    INVALID_SUB;
}
